   #include <memory>
    #include <cppunit/extensions/TestFactoryRegistry.h>
    #include <cppunit/ui/text/TestRunner.h>
    #include <cppunit/CompilerOutputter.h>
    #include <cppunit/TestCase.h>
    #include <cppunit/extensions/HelperMacros.h>

#include <list>


#include <nemosomenBase.h>




class TestModel : public Model {
public:
	Prop<int> *int1;
	Prop<int> *int2;
	
	Prop<float> *float1;
	Prop<float> *float2;
	
	Prop<double> *double1;
	Prop<double> *double2;
	
	Prop<long> *long1;
	Prop<long> *long2;
	
	Prop<std::string> *string1;
	Prop<std::string> *string2;
	
	Prop<TestModel*> *model1;
	Prop<TestModel*> *model2;
	
	NProp<int> *npropInt;
	NProp<TestModel*> *npropModel;
	
	TestModel(DataPool *pool,std::string name):Model(pool,name) {
		int1 = new Prop<int>(INT,"int1",this);
		int2 = new Prop<int>(INT,"int2",this);
		
		float1 = new Prop<float>(FLOAT,"float1",this);
		float2 = new Prop<float>(FLOAT,"float2",this);
		
		double1 = new Prop<double>(DOUBLE,"double1",this);
		double2 = new Prop<double>(DOUBLE,"double2",this);
		
		long1 = new Prop<long>(LONG,"long1",this);
		long2 = new Prop<long>(LONG,"long2",this);
		
		string1 = new Prop<std::string>(TEXT,"string1",this);
		string2 = new Prop<std::string>(TEXT,"string2",this);
		
		model1 = new Prop<TestModel*>(MODEL,"model1",this);
		model2 = new Prop<TestModel*>(MODEL,"model2",this);
		
		npropInt = new NProp<int>(INT,"npropInt",this);
		npropModel = new NProp<TestModel*>(MODEL,"npropModel",this);
	}
};




    class ExampleTestCase : public CppUnit::TestCase ,public  Runnable
    {


      CPPUNIT_TEST_SUITE( ExampleTestCase );
      CPPUNIT_TEST( set );
      CPPUNIT_TEST( testProperties );
      CPPUNIT_TEST( testDynamic );
      CPPUNIT_TEST( testConstraints );
      CPPUNIT_TEST( testConnector );
      CPPUNIT_TEST( testLock );
      CPPUNIT_TEST( testModules );
      CPPUNIT_TEST( testValueHandler );
      CPPUNIT_TEST( testNProp );
      CPPUNIT_TEST( testWalker );
      CPPUNIT_TEST_SUITE_END();

      DataPool *pool;
      TestModel *model;
      ModulePool *modulePool;
    	void			set ();
    	void			testProperties();
    	void 			testDynamic();
    	void			testConstraints();
    	void			testConnector();
    	void			testLock();
    	void			testModules();
    	void			testValueHandler();
    	void			testNProp();
    	void			testWalker();

    public:

    	void			transactionThread();
    	void			setUp ();
    	void			run ();
    };




    CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( ExampleTestCase, "ExampleTestCase" );


    void ExampleTestCase::setUp ()
    {
    	pool = new DataPool();
    	model = new TestModel(pool,"m1");
    	modulePool = new ModulePool(pool,"modulePool");
    	
    }
    

    
    void ExampleTestCase::run() {
    	Logger::log("enterThread:");
    	pool->initTransaction();
    	model->int1->set(23);
    	CPPUNIT_ASSERT(model->int1->get()==23);
    	usleep(25);
    	Logger::logInt("logThread",model->int1->get());
    	pool->closeTransaction();
    }

    void ExampleTestCase::testNProp() {
    	model->npropInt->append(23);
    	model->npropInt->append(24);
    	CPPUNIT_ASSERT(model->npropInt->get(0)==23);
    	CPPUNIT_ASSERT(model->npropInt->get(1)==24);
    }
    
    void ExampleTestCase::testWalker() {
    	std::list<AbstractProp*> *l = model->getProps();
    	std::list<AbstractProp*>::iterator it;
    	for (it = l->begin();it!=l->end();it++) {
    		AbstractProp *p = (AbstractProp*)*it;
    		printf("Type: %uc\n",p->getType());
    	}
    }
    
    void ExampleTestCase::testValueHandler() {
    	ValueHandler<std::string> vH = ValueHandler<std::string>(AttributeHolder::REQUEST);
    	std::string s = "Test1";
    	AttributeHolder *aH = new AttributeHolder(0);
    	vH.set(aH,&s);
    	std::string *t = vH.get(aH);
    	CPPUNIT_ASSERT(*t==s);
    	t = (std::string*)aH->getRequestAttribute("xxx");
    	CPPUNIT_ASSERT(t==0);
    }
    
    void ExampleTestCase::testModules() {
    	TimeImport::importModule(pool);
    	ModuleListener *listener = new ModuleListener();
    	modulePool->newModule->addConsumer(listener);
    	modulePool->newModule->set(new TimerConfig(pool,"timer1",40));
    	
    	
    	delete listener;
    }
    
    void ExampleTestCase::testLock() {
    	
    	TimeImport::importModule(pool);
    	
    	model->int1->set(5);
    	start();
    	usleep(10);
    	CPPUNIT_ASSERT(model->int1->get()==5);
    	model->int1->set(15);
    	CPPUNIT_ASSERT(model->int1->get()==5);
    	Logger::logInt("log",model->int1->get());
    	wait();
    	CPPUNIT_ASSERT(model->int1->get()==23);
    	model->int1->set(15);
    	CPPUNIT_ASSERT(model->int1->get()==15);
    	
//    	Timer *t = (Timer*)pool->createModule(new TimerConfig(pool,"timer1",40));
//    	TimeSelectorListener *tLis = (TimeSelectorListener*)pool->createModule(new ModuleConfig(pool,"sel1",MODULE_TIME_SELECTOR_LISTENER));
//    	ThreadedTimeSelector *sel = (ThreadedTimeSelector*)pool->createModule(new ModuleConfig(pool,"thread1",MODULE_TIME_THREADED_SELECTOR));
//    	TestLongListener *sel = (TestLongListener*)pool->createModule(new ModuleConfig(pool,"long1",MODULE_TIME_DEBUG_LONG_LISTENER));
    	
    	Timer *t = new Timer(new TimerConfig(pool,"timer1",40));
    	TimeSelectorListener *tLis = new TimeSelectorListener(new ModuleConfig(pool,"sel1"));
    	ThreadedTimeSelector *sel = new ThreadedTimeSelector(new ModuleConfig(pool,"thread1"));
    	TestLongListener *longLis = new TestLongListener(new ModuleConfig(pool,"long1"));
    	
    	t->conf()->time->addConsumer(tLis);
    	tLis->addTimeSelector(sel);
    	sel->setListener(longLis);
    	
    	t->start();
    	t->wait();
    	
    	
    	Module *mod = pool->createModule(new ModuleConfig(pool,"name","module"));
    	printf("hui %s\n",mod->getModuleName().data());
    	
    	
    	ModelImport::importModel(pool);
    	
    	
    	MidiReader *mR = new MidiReader("/dev/midi1");
    	mR->start();
    	
    	mR->wait();
    }

    void ExampleTestCase::testConnector() {
    	Connector<int> *con = new Connector<int>(model->int2);
    	model->int1->addConsumer(con);
    	model->int1->set(23);
    	CPPUNIT_ASSERT(model->int2->get()==23);
    	model->int1->removeConsumer(con);
    	model->int1->set(24);
    	CPPUNIT_ASSERT(model->int2->get()==23);
    	
    	Connector<float> *conF = new Connector<float>(model->float2);
    	model->float1->addConsumer(conF);
    	model->float1->set(23.0);
    	CPPUNIT_ASSERT(model->float2->get()==23.0);
    	model->float1->removeConsumer(conF);
    	model->float1->set(24.0);
    	CPPUNIT_ASSERT(model->float2->get()==23.0);
    	
    	Connector<double> *conD = new Connector<double>(model->double2);
    	model->double1->addConsumer(conD);
    	model->double1->set(23.0);
    	CPPUNIT_ASSERT(model->double2->get()==23.0);
    	model->double1->removeConsumer(conD);
    	model->double1->set(24.0);
    	CPPUNIT_ASSERT(model->double2->get()==23.0);
    	
    	Connector<long> *conL = new Connector<long>(model->long2);
    	model->long1->addConsumer(conL);
    	model->long1->set(23);
    	CPPUNIT_ASSERT(model->long2->get()==23);
    	model->long1->removeConsumer(conL);
    	model->long1->set(24);
    	CPPUNIT_ASSERT(model->long2->get()==23);
    	
    	Connector<std::string> *conS = new Connector<std::string>(model->string2);
    	model->string1->addConsumer(conS);
    	model->string1->set("23");
    	CPPUNIT_ASSERT(model->string2->get()=="23");
    	model->string1->removeConsumer(conS);
    	model->string1->set("24");
    	CPPUNIT_ASSERT(model->string2->get()=="23");
    	
    	TestModel *mod1 = new TestModel(pool,"m2");
    	TestModel *mod2 = new TestModel(pool,"m3");
    	Connector<TestModel*> *conT = new Connector<TestModel*>(model->model2);
    	model->model1->addConsumer(conT);
    	model->setModel("model1",mod1);
    	CPPUNIT_ASSERT(model->model2->get() == mod1);
    	model->model1->removeConsumer(conT);
    	model->setModel("model1",mod2);
    	
    	CPPUNIT_ASSERT(model->model2->get() == mod1);

    	free(mod1);
    	free(mod2);
    	
    	
    }
    void ExampleTestCase::testConstraints() {
    	MinMaxConstraint *con = new MinMaxConstraint(10,20); 
    	model->int1->set(15);
    	CPPUNIT_ASSERT (model->int1->get() == 15);
    	model->int1->addConstraint(con);
    	model->int1->set(25);
    	CPPUNIT_ASSERT (model->int1->get() == 15);
    	model->int1->set(5);
    	CPPUNIT_ASSERT (model->int1->get() == 15);
    	model->int1->removeConstraint(con);
    	model->int1->set(5);
    	CPPUNIT_ASSERT (model->int1->get() == 5);
    	
    	model->long1->set(15);
    	CPPUNIT_ASSERT (model->long1->get() == 15);
    	model->long1->addConstraint(con);
    	model->long1->set(25);
    	CPPUNIT_ASSERT (model->long1->get() == 15);
    	model->long1->set(5);
    	CPPUNIT_ASSERT (model->long1->get() == 15);
    	model->long1->removeConstraint(con);
    	model->long1->set(5);
    	CPPUNIT_ASSERT (model->long1->get() == 5);
    	
    	model->float1->set(15.0);
    	CPPUNIT_ASSERT (model->float1->get() == 15.0);
    	model->float1->addConstraint(con);
    	model->float1->set(25.0);
    	CPPUNIT_ASSERT (model->float1->get() == 15.0);
    	model->float1->set(5.0);
    	CPPUNIT_ASSERT (model->float1->get() == 15.0);
    	model->float1->removeConstraint(con);
    	model->float1->set(5.0);
    	CPPUNIT_ASSERT (model->float1->get() == 5.0);
    	
    	model->double1->set(15.0);
    	CPPUNIT_ASSERT (model->double1->get() == 15.0);
    	model->double1->addConstraint(con);
    	model->double1->set(25.0);
    	CPPUNIT_ASSERT (model->double1->get() == 15.0);
    	model->double1->set(5.0);
    	CPPUNIT_ASSERT (model->double1->get() == 15.0);
    	model->double1->removeConstraint(con);
    	model->double1->set(5.0);
    	CPPUNIT_ASSERT (model->double1->get() == 5.0);
    }
    
    void ExampleTestCase::testDynamic() {
    	model->setInt("int1",10);
    	model->setInt("int2",20);
    	CPPUNIT_ASSERT (model->int1->get() == 10);
    	CPPUNIT_ASSERT (model->int2->get() == 20);   
    	CPPUNIT_ASSERT (model->getInt("int1") == 10);
    	CPPUNIT_ASSERT (model->getInt("int2") == 20);  

    	model->setDouble("double1",30.0);
    	model->setDouble("double2",40.0);
    	CPPUNIT_ASSERT(model->double1->get() == 30.0);
    	CPPUNIT_ASSERT(model->double2->get() == 40.0);
    	CPPUNIT_ASSERT(model->getDouble("double1") == 30.0);
    	CPPUNIT_ASSERT(model->getDouble("double2") == 40.0);

    	model->setFloat("float1",50.0);
    	model->setFloat("float2",60.0);
    	CPPUNIT_ASSERT(model->float1->get() == 50.0);
    	CPPUNIT_ASSERT(model->float2->get() == 60.0);
    	CPPUNIT_ASSERT(model->getFloat("float1") == 50.0);
    	CPPUNIT_ASSERT(model->getFloat("float2") == 60.0);

    	model->setLong("long1",70);
    	model->setLong("long2",80);
    	CPPUNIT_ASSERT (model->long1->get() == 70);
    	CPPUNIT_ASSERT (model->long2->get() == 80);  
    	CPPUNIT_ASSERT (model->getLong("long1") == 70);
    	CPPUNIT_ASSERT (model->getLong("long2") == 80);  

    	model->setString("string1","10");
    	model->setString("string2","20");
    	CPPUNIT_ASSERT (model->string1->get() == "10");
    	CPPUNIT_ASSERT (model->string2->get() == "20");
    	CPPUNIT_ASSERT (model->getString("string1") == "10");
    	CPPUNIT_ASSERT (model->getString("string2") == "20");
    	
    	TestModel *mod1 = new TestModel(pool,"m2");
    	TestModel *mod2 = new TestModel(pool,"m3");
    	model->setModel("model1",mod1);
    	model->setModel("model2",mod2);
    	CPPUNIT_ASSERT(model->model1->get() == mod1);
    	CPPUNIT_ASSERT(model->model2->get() == mod2);
    	CPPUNIT_ASSERT(model->getModel("model1") == mod1);
    	CPPUNIT_ASSERT(model->getModel("model2") == mod2);
    	model->getModel("model1")->setInt("int1",23);
    	CPPUNIT_ASSERT(model->model1->get()->int1->get()==23);
    	free(mod1);
    	free(mod2);
    }
    
    void ExampleTestCase::testProperties() {
    	model->int1->set(1);
    	model->int2->set(2);
    	CPPUNIT_ASSERT (model->int1->get() == 1);
    	CPPUNIT_ASSERT (model->int2->get() == 2);   
    	
    	model->double1->set(3.0);
    	model->double2->set(4.0);
    	CPPUNIT_ASSERT(model->double1->get() == 3.0);
    	CPPUNIT_ASSERT(model->double2->get() == 4.0);
    	
    	model->float1->set(5.0);
    	model->float2->set(6.0);
    	CPPUNIT_ASSERT(model->float1->get() == 5.0);
    	CPPUNIT_ASSERT(model->float2->get() == 6.0);
    	
    	model->long1->set(7);
    	model->long2->set(8);
    	CPPUNIT_ASSERT (model->long1->get() == 7);
    	CPPUNIT_ASSERT (model->long2->get() == 8);  
    	
    	model->string1->set("1");
    	model->string2->set("2");
    	CPPUNIT_ASSERT (model->string1->get() == "1");
    	CPPUNIT_ASSERT (model->string2->get() == "2");
    	
    	
    	TestModel *mod1 = new TestModel(pool,"m2");
    	TestModel *mod2 = new TestModel(pool,"m3");
    	
    	model->model1->set(mod1);
    	model->model2->set(mod2);
    	CPPUNIT_ASSERT(model->model1->get() == mod1);
    	CPPUNIT_ASSERT(model->model2->get() == mod2);
    	free(mod1);
    	free(mod2);
    }
    
    void ExampleTestCase::set ()
    {
    	
    	Value<int> *intVal = new Value<int>(3,3000,INT);
    	CPPUNIT_ASSERT(intVal->getValue()==3);
    	CPPUNIT_ASSERT(intVal->getTimestamp()==3000);
    	CPPUNIT_ASSERT(intVal->getValueType()==INT);
    	
    	ValueContainer *c = new ValueContainer((int)intVal,intVal->getValueType());
    	
    	std::list<ValueContainer* > valueSet;
    	
    	valueSet.push_back(c);
    	Value<int> *intVal2 = (Value<int>*)c->getPointer();
    	CPPUNIT_ASSERT(intVal->getValue()==intVal2->getValue());
    	CPPUNIT_ASSERT(intVal->getValueType()|INT == intVal->getValueType());
    	CPPUNIT_ASSERT(intVal->getValueType()|FLOAT == intVal->getValueType());
    	
    	TestIntListener *lis = new TestIntListener;
    	unsigned int i=1;
    	lis->valueChanged(1L,i,c);
    	model->int1->set(23);
    	CPPUNIT_ASSERT(model->int1->get()==23);
    	model->int1->addConsumer(lis);
    	model->int1->set(24);	
    	model->int1->removeConsumer(lis);  	
    	model->int1->set(25);  	
    	model->int2->set(1);
    	
    	AbstractProp *vCon = model->getProp(0); 
    	Prop<int> *pi = (Prop<int>*)vCon;
    	CPPUNIT_ASSERT(pi->get()==25);
    	
    	AbstractProp *vCon2 = model->getProp("int2"); 
    	Prop<int> *pi2 = (Prop<int>*)vCon2;
    	CPPUNIT_ASSERT(pi2->get()==1);
    	CPPUNIT_ASSERT(pi->get()==25);


    	CPPUNIT_ASSERT(1==1);
    }

 

    
    
    CppUnit::Test *suite()
    {
      CppUnit::TestFactoryRegistry &registry =
                          CppUnit::TestFactoryRegistry::getRegistry();


      registry.registerFactory(
          &CppUnit::TestFactoryRegistry::getRegistry( "ExampleTestCase" ) );
      return registry.makeTest();
    }



    int main( int argc, char* argv[] )
    {
      // if command line contains "-selftest" then this is the post build check
      // => the output must be in the compiler error format.
      bool selfTest = (argc > 1)  &&
                      (std::string("-selftest") == argv[1]);


      CppUnit::TextUi::TestRunner runner;
      runner.addTest( suite() );   // Add the top suite to the test runner


      if ( selfTest )
      { // Change the default outputter to a compiler error format outputter
        // The test runner owns the new outputter.
        runner.setOutputter( CppUnit::CompilerOutputter::defaultOutputter(
                                                            &runner.result(),
                                                            std::cerr ) );
      }


      // Run the test.
      bool wasSucessful = runner.run( "" );


      // Return error code 1 if any tests failed.
      return wasSucessful ? 0 : 1;
    }